package com.dd.keel.core.common.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStreamReader;
import java.io.BufferedReader;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * SQL template util
 * Encoding is UTF-8
 * @author Kevin.XU
 *
 */

public class SqlReader {
	
	final static private Logger LOGGER = LoggerFactory.getLogger(SqlReader.class);
	
	private String BEGIN_FLAG = "--BEGIN";
	private String END_FLAG = "--END";
	private String COMMENT_FLAG = "--";
	
	private int STATUS_VALID = 1;
	private int STATUS_INVALID = 2;
	
	private char VARIABLE_BEGIN_FLAG = '{';
	private char VARIABLE_END_FLAG = '}';
	
	private String sql_file_name = null;
	private String encoding = "UTF-8";
	
	private HashMap sqlMap = new HashMap();
	
	private boolean inited = false;
	
	private Class contextClass = null;
	
	private static Map<String,SqlReader> cache_sqlreaders = Collections.synchronizedMap(new HashMap<String,SqlReader>());
	
	public static SqlReader getSqlReader(String sql_file_name,Class contextClass)
	{
		SqlReader reader = cache_sqlreaders.get(sql_file_name);
		if(reader!=null)
		{
			return reader;
		}
		synchronized(cache_sqlreaders)
		{
			//check again, because when current thread is waitting lock, may be other thread have created the same sql reader 
			reader = cache_sqlreaders.get(sql_file_name);
			if(reader!=null)
			{
				return reader;
			}
			else
			{
				SqlReader sqlReader = new SqlReader(sql_file_name,contextClass);
				sqlReader.init();
				cache_sqlreaders.put(sql_file_name, sqlReader);
				return sqlReader;
			}
		}
	}
	
	private SqlReader(String sql_file_name,Class contextClass)
	{
		this.sql_file_name = sql_file_name;
		this.contextClass = contextClass;
	}
	
	private void init()
	{
		if(inited) return;
		InputStreamReader isr = null;
		BufferedReader br = null;
		try{
			isr = new InputStreamReader(URLUtil.getURLFromClasspath(sql_file_name,contextClass).openStream(),encoding);
			br = new BufferedReader(isr);
			String lineStr = null;
			StringBuffer sb = new StringBuffer();
			int status = STATUS_INVALID;
			String key = null;
			while((lineStr = br.readLine())!=null)
			{
				lineStr = lineStr.trim();
				if(lineStr.equals("")) continue;
				if(lineStr.startsWith(BEGIN_FLAG)){
					int pos = lineStr.indexOf(":");
					if(pos!=-1 && pos!= lineStr.length()-1 ){
						status = STATUS_VALID;
						key = lineStr.split("\\:")[1];
					}
					continue;
				}
				if(lineStr.startsWith(END_FLAG)){
					if(status==STATUS_VALID){
						status = STATUS_INVALID;
						String sql = sb.toString();
						sqlMap.put(key,sql);
						sb.delete(0,sql.length());
					}
					continue;
				}
				if(status==STATUS_VALID){
					lineStr = lineStr.replaceAll("\t"," ");
					if(!lineStr.startsWith(COMMENT_FLAG)){
						sb.append(lineStr).append(" ");
					}
				}
			}
		}catch(Exception ex){
			LOGGER.error( ex.getMessage(), ex );
		}finally{
			try{
				br.close();
			}catch(Exception ex){}
			try{
				isr.close();
			}catch(Exception ex){}
		}
		inited = true;
	}
	
	public String getSqlStr(String key)
	{
		init();
		Object obj = sqlMap.get(key);
		if(obj!=null){
			return (String)obj;
		}else{
			return null;
		}
	}
	
	public String getSqlStr(String key,Map markValues)
	{
		String sql = getSqlStr(key);
		if(sql!=null){
			StringBuilder sb = new StringBuilder();
			int status = STATUS_VALID;
			String macroName = "";
			for(int i=0; i<sql.length(); i++)
			{
				char temp = sql.charAt(i);
				if(temp==VARIABLE_BEGIN_FLAG){
					status = STATUS_INVALID;
					continue;
				}
				if(temp==VARIABLE_END_FLAG){
					status = STATUS_VALID;
					Object obj = markValues.get(macroName);
					if(obj==null){
						sb.append(VARIABLE_BEGIN_FLAG).append(macroName).append(VARIABLE_END_FLAG);
					}else{
						sb.append(String.valueOf(obj));
					}
					macroName = "";
					continue;
				}
				if(status==STATUS_VALID){
					sb.append(temp);
				}
				if(status==STATUS_INVALID){
					macroName += temp;
				}
			}
			return sb.toString();
		}else{
			return null;
		}
	}
	
	
}
